<!DOCTYPE html>

















































<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

  <meta name="description" content="Javadoc API documentation for Dormancy." />

<link rel="shortcut icon" type="image/x-icon" href="../../favicon.ico" />
<title>

  Dormancy


| Dormancy

</title>
<link href="../../../assets/doclava-developer-docs.css" rel="stylesheet" type="text/css" />
<link href="../../../assets/customizations.css" rel="stylesheet" type="text/css" />
<script src="../../../assets/search_autocomplete.js" type="text/javascript"></script>
<script src="../../../assets/jquery-resizable.min.js" type="text/javascript"></script>
<script src="../../../assets/doclava-developer-docs.js" type="text/javascript"></script>
<script src="../../../assets/prettify.js" type="text/javascript"></script>
<script type="text/javascript">
  setToRoot("../../", "../../../assets/");
</script>
<script src="../../../assets/doclava-developer-reference.js" type="text/javascript"></script>
<script src="../../../assets/navtree_data.js" type="text/javascript"></script>
<script src="../../../assets/customizations.js" type="text/javascript"></script>
<noscript>
  <style type="text/css">
    html,body{overflow:auto;}
    #body-content{position:relative; top:0;}
    #doc-content{overflow:visible;border-left:3px solid #666;}
    #side-nav{padding:0;}
    #side-nav .toggle-list ul {display:block;}
    #resize-packages-nav{border-bottom:3px solid #666;}
  </style>
</noscript>
</head>

<body class="">

<div id="header">
    <div id="headerLeft">
    
      <span id="masthead-title">Dormancy</span>
    
    </div>
    <div id="headerRight">
      
  <div id="search" >
      <div id="searchForm">
          <form accept-charset="utf-8" class="gsc-search-box" 
                onsubmit="return submit_search()">
            <table class="gsc-search-box" cellpadding="0" cellspacing="0"><tbody>
                <tr>
                  <td class="gsc-input">
                    <input id="search_autocomplete" class="gsc-input" type="text" size="33" autocomplete="off"
                      title="search developer docs" name="q"
                      value="search developer docs"
                      onFocus="search_focus_changed(this, true)"
                      onBlur="search_focus_changed(this, false)"
                      onkeydown="return search_changed(event, true, '../../')"
                      onkeyup="return search_changed(event, false, '../../')" />
                  <div id="search_filtered_div" class="no-display">
                      <table id="search_filtered" cellspacing=0>
                      </table>
                  </div>
                  </td>
                  <td class="gsc-search-button">
                    <input type="submit" value="Search" title="search" id="search-button" class="gsc-search-button" />
                  </td>
                  <td class="gsc-clear-button">
                    <div title="clear results" class="gsc-clear-button">&nbsp;</div>
                  </td>
                </tr></tbody>
              </table>
          </form>
      </div><!-- searchForm -->
  </div><!-- search -->
      
    </div>
</div><!-- header -->


  <div class="g-section g-tpl-240" id="body-content">
    <div class="g-unit g-first side-nav-resizable" id="side-nav">
      <div id="swapper">
        <div id="nav-panels">
          <div id="resize-packages-nav">
            <div id="packages-nav">
              <div id="index-links"><nobr>
                <a href="../../packages.html"  >Package Index</a> | 
                <a href="../../classes.html" >Class Index</a></nobr>
              </div>
              <ul>
                
    <li class="selected api apilevel-">
  <a href="../../at/dormancy/package-summary.html">at.dormancy</a></li>
    <li class="api apilevel-">
  <a href="../../at/dormancy/access/package-summary.html">at.dormancy.access</a></li>
    <li class="api apilevel-">
  <a href="../../at/dormancy/aop/package-summary.html">at.dormancy.aop</a></li>
    <li class="api apilevel-">
  <a href="../../at/dormancy/persistence/package-summary.html">at.dormancy.persistence</a></li>
    <li class="api apilevel-">
  <a href="../../at/dormancy/persister/package-summary.html">at.dormancy.persister</a></li>
    <li class="api apilevel-">
  <a href="../../at/dormancy/persister/callback/package-summary.html">at.dormancy.persister.callback</a></li>
    <li class="api apilevel-">
  <a href="../../at/dormancy/persister/filter/package-summary.html">at.dormancy.persister.filter</a></li>
    <li class="api apilevel-">
  <a href="../../at/dormancy/persister/function/package-summary.html">at.dormancy.persister.function</a></li>
    <li class="api apilevel-">
  <a href="../../at/dormancy/persister/predicate/package-summary.html">at.dormancy.persister.predicate</a></li>
    <li class="api apilevel-">
  <a href="../../at/dormancy/util/package-summary.html">at.dormancy.util</a></li>
              </ul><br/>
            </div> <!-- end packages -->
          </div> <!-- end resize-packages -->
          <div id="classes-nav">
            <ul>
              
              
    <li><h2>Classes</h2>
      <ul>
          <li class="selected api apilevel-"><a href="../../at/dormancy/Dormancy.html">Dormancy</a>&lt;PU,&nbsp;PC,&nbsp;PMD&gt;</li>
          <li class="api apilevel-"><a href="../../at/dormancy/EntityPersisterConfiguration.html">EntityPersisterConfiguration</a></li>
          <li class="api apilevel-"><a href="../../at/dormancy/HibernateDormancy.html">HibernateDormancy</a></li>
      </ul>
    </li>
              
              
              
              
            </ul><br/>
          </div><!-- end classes -->
        </div><!-- end nav-panels -->
        <div id="nav-tree" style="display:none">
          <div id="index-links"><nobr>
            <a href="../../packages.html"  >Package Index</a> | 
            <a href="../../classes.html" >Class Index</a></nobr>
          </div>
        </div><!-- end nav-tree -->
      </div><!-- end swapper -->
    </div> <!-- end side-nav -->
    <script>
      if (!isMobile) {
        $("<a href='#' id='nav-swap' onclick='swapNav();return false;' style='font-size:10px;line-height:9px;margin-left:1em;text-decoration:none;'><span id='tree-link'>Use Tree Navigation</span><span id='panel-link' style='display:none'>Use Panel Navigation</span></a>").appendTo("#side-nav");
        chooseDefaultNav();
        if ($("#nav-tree").is(':visible')) {
          init_default_navtree("../../");
        } else {
          addLoadEvent(function() {
            scrollIntoView("packages-nav");
            scrollIntoView("classes-nav");
          });
        }
        $("#swapper").css({borderBottom:"2px solid #aaa"});
      } else {
        swapNav(); // tree view should be used on mobile
      }
    </script>



<div class="g-unit" id="doc-content">

<div id="api-info-block">



  
   
  
  
  
   
  
  

  
   
  
  
  
  

  
   
  
  
  
  

  
  
  
  

  
   
  
  
  
  


<div class="sum-details-links">

<div>
<a href="Dormancy.html">View Documentation</a>
</div>


</div><!-- end sum-details-links -->
<div class="api-level">
  


  
  

</div>
</div><!-- end api-info-block -->


<!-- ======== START OF CLASS DATA ======== -->

<div id="jd-header">
    public
     
     
    
    class
<h1>Dormancy</h1>



  
  
  

  
    extends <a href="../../at/dormancy/persister/AbstractEntityPersister.html">AbstractEntityPersister</a>&lt;C&gt;<br/>
  
  
  

  
  
      implements 
      
        ApplicationContextAware 
      
  
  


</div><!-- end header -->
<div id="jd-content">
  <pre class="prettyprint">
/*
 * Copyright 2013 Gregor Schauer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package at.dormancy;

import at.dormancy.persistence.PersistenceUnitProvider;
import at.dormancy.persister.*;
import at.dormancy.persister.callback.EntityCallback;
import at.dormancy.util.AbstractDormancyUtils;
import at.dormancy.util.ClassLookup;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang.reflect.ConstructorUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyAccessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.CollectionFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Clones Hibernate entities and merges them into a persistence context.&lt;br/&gt;
 *
 * @author Gregor Schauer
 * @see EntityPersister
 */
public class Dormancy&lt;PU, PC, PMD&gt; extends AbstractEntityPersister&lt;Object&gt; implements ApplicationContextAware {
	protected static final Logger logger = Logger.getLogger(Dormancy.class);
	protected Map&lt;Class&lt;?&gt;, AbstractEntityPersister&lt;?&gt;&gt; persisterMap;
	protected PersistenceUnitProvider&lt;PU, PC, PMD&gt; persistenceUnitProvider;
	protected EntityPersisterConfiguration config;
	protected AbstractDormancyUtils&lt;PU, PC, PMD, PersistenceUnitProvider&lt;PU, PC, PMD&gt;&gt; utils;
	protected boolean registerDefaultEntityPersisters = true;

	@Inject
	public Dormancy(@Nonnull PersistenceUnitProvider&lt;PU, PC, PMD&gt; persistenceUnitProvider) {
		this.persistenceUnitProvider = persistenceUnitProvider;
	}

	/**
	 * Initializes this instance.&lt;br/&gt;
	 * If no {@link EntityPersisterConfiguration} is set, a default configuration is created.
	 */
	@PostConstruct
	@SuppressWarnings("unchecked")
	public void initialize() {
		// Initialize JPA provider specific DormancyUtils
		if (utils == null) {
			String className = "at.dormancy.util.DormancyUtils";
			Class&lt;?&gt; type = ClassLookup.find(className).orThrow(
					"Cannot initialize Dormancy: Missing class \"%s\"\n" +
							"Please make sure that there is exactly one Dormancy backend in the classpath.\n" +
							"Official implementations are:\n" +
							"x) hibernate3\n" +
							"x) hibernate4\n" +
							"x) jpa-hibernate\n" +
							"x) jpa-eclipselink\n", className).get();

			Constructor&lt;? extends AbstractDormancyUtils&gt; ctor = ConstructorUtils.getAccessibleConstructor(
					type, persistenceUnitProvider.getClass());
			utils = BeanUtils.instantiateClass(ctor, persistenceUnitProvider);
		}

		// Ensure that a configuration is provided
		if (config == null) {
			config = new EntityPersisterConfiguration();
		}

		// Register all default entity persisters if necessary
		if (registerDefaultEntityPersisters) {
			addEntityPersister(ArrayPersister.class);
			addEntityPersister(CollectionPersister.class);
			addEntityPersister(MapPersister.class);
			addEntityPersister(NoOpPersister.class);
		}
	}

	@Nullable
	@Override
	public final &lt;T&gt; T clone(@Nullable T dbObj) {
		return clone_(dbObj, createAdjacencyMap());
	}

	@Nullable
	@Override
	@SuppressWarnings("unchecked")
	public &lt;T&gt; T clone_(@Nullable T dbObj, @Nonnull Map&lt;Object, Object&gt; tree) {
		// Check if the object has already been processed
		if (tree.containsKey(dbObj) || dbObj == null) {
			return (T) tree.get(dbObj);
		}

		// Use an EntityPersister if possible
		AbstractEntityPersister&lt;T&gt; entityPersister = getEntityPersister((Class&lt;T&gt;) dbObj.getClass());
		if (entityPersister != null) {
			if (logger.isDebugEnabled()) {
				logger.debug(String.format("Using %s for %s", entityPersister.getClass().getSimpleName(), dbObj));
				if (logger.isTraceEnabled()) {
					try {
						logger.trace(org.apache.commons.beanutils.BeanUtils.describe(dbObj));
					} catch (Exception e) {
						// ignore
					}
				}
			}
			return entityPersister.clone_(dbObj, tree);
		}

		// Create a new instance of the same type
		T trObj = config.getCloneObjects() || utils.isJavassistProxy(dbObj.getClass()) ? (T) BeanUtils.instantiateClass(utils.getClass(dbObj)) : dbObj;

		// Add the object to the adjacency list
		tree.put(dbObj, trObj);

		// If automatic flushing is enabled, flush the persistence context to make sure that there are no pending changes
		if (config.getFlushAutomatically()) {
			utils.flush();
		}

		// Retrieve the Hibernate class metadata (if available)
		PMD metadata = utils.getMetadata(dbObj);

		// Process the properties
		String[] propertyNames = utils.getPropertyNames(dbObj);
		PropertyAccessor dbPropertyAccessor;
		try {
			dbPropertyAccessor = utils.getPropertyAccessor(metadata, dbObj);
		} catch (Exception e) {
			logger.warn(String.format("Cannot access object %s: %s", ObjectUtils.identityToString(dbObj), ExceptionUtils.getMessage(e)));
			tree.put(dbObj, null);
			return null;
		}
		PropertyAccessor trPropertyAccessor = dbObj == trObj ? dbPropertyAccessor : utils.getPropertyAccessor(metadata, trObj);
		for (String propertyName : propertyNames) {
			if (utils.isTransient(dbObj, propertyName)) {
				continue;
			}

			Object dbValue;
			try {
				dbValue = dbPropertyAccessor.getPropertyValue(propertyName);
			} catch (BeansException e) {
				if (metadata != null) {
					/**
					 * If the property value cannot bet read and the object is a Hibernate entity, throw an exception.
					 * Note that this is a security mechanism to ensure database consistency.
					 * Otherwise it would be possible that references, which are not initialized properly,
					 * cause constraint violations or even delete associations.
					 */
					throw e;
				} else if (logger.isDebugEnabled()) {
					// If the property value of a non entity cannot be read, write a debug message to the log.
					logger.debug(ExceptionUtils.getMessage(e));
				}
				continue;
			}

			Object trValue = null;
			// If the property (e.g., a lazy persistent collection) is initialized traverse the object graph recursively
			if (dbValue != null) {
				if (utils.isInitialized(dbValue)) {
					trValue = clone_((T) dbValue, tree);
				} else if (utils.isPersistentCollection(dbValue) &amp;&amp; config.getCreateEmptyCollections()) {
					trValue = dbValue instanceof Map
							? CollectionFactory.createApproximateMap(dbValue, 0)
							: CollectionFactory.createApproximateCollection(dbValue, 0);
				}
			}

			if (logger.isTraceEnabled()) {
				logger.trace(String.format("Setting property %s of %s to %s", propertyName, trObj, trValue));
			}

			// Attempt to set the property value
			try {
				trPropertyAccessor.setPropertyValue(propertyName, trValue);
			} catch (BeansException e) {
				if (metadata != null) {
					/**
					 * If the property value cannot bet set and the object is a Hibernate entity, throw an exception.
					 * Note that this is a security mechanism to ensure database consistency.
					 * Otherwise it would be possible that references, which are not initialized properly,
					 * cause constraint violations or even delete associations.
					 */
					throw e;
				} else if (logger.isEnabledFor(Level.WARN)) {
					// If the property value of a non entity cannot be set, write a warning to the log.
					logger.warn(ExceptionUtils.getMessage(e));
				}
			}
		}

		return trObj;
	}

	@Nullable
	@Override
	public final &lt;T&gt; T merge(@Nullable T trObj) {
		return merge_(trObj, createAdjacencyMap());
	}

	@Nullable
	@Override
	@SuppressWarnings("unchecked")
	public &lt;T&gt; T merge_(@Nullable T trObj, @Nonnull Map&lt;Object, Object&gt; tree) {
		// Check if the object has already been processed
		if (tree.containsKey(trObj) || trObj == null) {
			return (T) tree.get(trObj);
		}

		// Use a EntityPersister if possible
		AbstractEntityPersister&lt;T&gt; entityPersister = getEntityPersister((Class&lt;? extends T&gt;) trObj.getClass());
		if (entityPersister != null) {
			if (logger.isDebugEnabled()) {
				logger.debug(String.format("Using %s for %s", entityPersister.getClass().getSimpleName(), trObj));
			}
			return entityPersister.merge_(trObj, tree);
		}

		// Verify that the given object is a non-null managed entity.
		PMD metadata = utils.getMetadata(trObj);
		if (metadata == null) {
			return trObj;
		}

		// Retrieve the identifier of the persistent object
		Serializable identifier = utils.getIdentifier(metadata, trObj);

		// If the identifier cannot be retrieved via getter, try to access it directly.
		if (identifier == null) {
			// If the object has no identifier, it is considered to be new
			if (config.getSaveNewEntities()) {
				// If desired, try to persist the object
				utils.persist(trObj);
				identifier = utils.getIdentifier(metadata, trObj);
			} else {
				// Otherwise throw an exception indicating that the entity should have be saved before
				throw utils.throwNullIdentifierException(trObj);
			}
		}

		// Retrieve the persistent object from the database
		T dbObj = (T) utils.find(utils.getClass(trObj), identifier);
		if (dbObj == null) {
			// Throw an exception indicating that the persistent object cannot be retrieved.
			throw utils.throwEntityNotFoundException(identifier, trObj);
		}

		return merge_(trObj, dbObj, tree);
	}

	/**
	 * Invokes the given {@link EntityCallback} and passes its result to {@link #merge(Object, Object)}.
	 *
	 * @param trObj    the object to merge
	 * @param callback the callback to execute
	 * @return the merged object
	 * @see #merge(Object, Object)
	 */
	@Nullable
	public final &lt;T&gt; T merge(@Nullable T trObj, @Nonnull EntityCallback&lt;T, PU, PC, PMD&gt; callback) {
		T dbObj = trObj == null ? null : callback.&lt;T&gt;work(persistenceUnitProvider);
		return merge(trObj, dbObj);
	}

	@Nullable
	@Override
	public final &lt;T&gt; T merge(@Nullable T trObj, @Nullable T dbObj) {
		return merge_(trObj, dbObj, createAdjacencyMap());
	}

	@Nullable
	@Override
	@SuppressWarnings("unchecked")
	public &lt;T&gt; T merge_(@Nullable T trObj, @Nullable T dbObj, @Nonnull Map&lt;Object, Object&gt; tree) {
		// Check if the object has already been processed
		if (tree.containsKey(trObj) || dbObj == null) {
			return (T) tree.get(trObj);
		}

		// Use an EntityPersister if possible
		AbstractEntityPersister&lt;T&gt; entityPersister = getEntityPersister(trObj != null ? (Class&lt;? extends T&gt;) trObj.getClass() : null);
		if (entityPersister != null) {
			if (logger.isDebugEnabled()) {
				logger.debug(String.format("Using %s for %s", entityPersister.getClass().getSimpleName(), trObj));
			}
			return entityPersister.merge_(trObj, dbObj, tree);
		}

		// Add the object to the adjacency list
		tree.put(trObj, dbObj);

		// Verify that the given object is a non-null managed entity or it is not necessary to merge it
		PMD metadata = utils.getMetadata(trObj);
		if (metadata == null || trObj == dbObj) {
			return trObj;
		}

		// Retrieve the identifier of the persistent object
		Serializable identifier = utils.getIdentifierValue(metadata, dbObj);

		// Compare the version property (if present and enabled)
		PropertyAccessor dbPropertyAccessor = utils.getPropertyAccessor(metadata, dbObj);
		PropertyAccessor trPropertyAccessor = utils.getPropertyAccessor(metadata, trObj);
		String[] propertyNames = utils.getPropertyNames(trObj);
		if (config.getCheckVersion() &amp;&amp; utils.isVersioned(metadata)) {
			Object dbValue = dbPropertyAccessor.getPropertyValue(utils.getVersionPropertyName(metadata));
			Object trValue = trPropertyAccessor.getPropertyValue(utils.getVersionPropertyName(metadata));
			if (dbValue != null &amp;&amp; !dbValue.equals(trValue)) {
				throw utils.throwOptimisticLockException(dbValue, identifier);
			}
		}

		// Process the properties
		for (int i = 0; i &lt; propertyNames.length; i++) {
			String propertyName = propertyNames[i];
			// Skip transient properties
			if (utils.isTransient(dbObj, propertyName)) {
				continue;
			}

			// Do not apply the version property if version checking is enabled
			String versionPropertyName = utils.getVersionPropertyName(metadata);
			if (propertyName.equals(versionPropertyName) &amp;&amp; config.getCheckVersion()) {
				continue;
			}

			// Read the property values
			Object trValue = trPropertyAccessor.getPropertyValue(propertyName);
			Object dbValue = dbPropertyAccessor.getPropertyValue(propertyName);
			Class&lt;?&gt; type = utils.getPropertyType(utils.getClass(dbObj), propertyName);

			// Lazily loaded collections are not copied
			if (Collection.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type)) {
				if (!utils.isInitializedPersistentCollection(dbValue)) {
					// If property is loaded lazily, the value of the given object must be null or empty
					if (trValue != null &amp;&amp; trValue != dbValue &amp;&amp; CollectionUtils.size(trValue) &gt; 0) {
						throw utils.throwLazyPropertyNotNullException(trValue, dbObj, propertyName);
					}
					continue;
				}
				trValue = merge_(trValue, dbValue, tree);
			}

			// Lazily loaded properties are not copied
			if (!ClassUtils.isPrimitiveOrWrapper(type) &amp;&amp; !type.getName().startsWith("java.") &amp;&amp; !type.isArray()) {
				// If the persistent value is a Hibernate proxy, it might be loaded lazily
				if (utils.isProxy(dbValue)) {
					if (utils.isUninitialized(propertyName, dbObj, dbValue, trValue)) {
						continue;
					}
				} else if (trValue != dbValue) {
					// Get the identifier of the associated transient object
					PMD valueMetadata = utils.getMetadata(dbValue);
					Serializable trValueId = Serializable.class.cast(utils.getIdentifier(valueMetadata, trValue));
					// Get the identifier of the associated persistent object
					Serializable dbValueId = Serializable.class.cast(utils.getIdentifier(valueMetadata, dbValue));

					// If the transient object is new
					if (trValueId == null) {
						if (config.getSaveNewEntities()) {
							// If desired, try to persist the object
							trValueId = utils.persist(trValue);
							trValue = utils.find(trValue.getClass(), trValueId);
						} else {
							// Otherwise throw an exception indicating that the entity should have been saved before
							throw utils.throwUnsavedTransientInstanceException(trValue);
						}
					} else if (!trValueId.equals(dbValueId)) {
						// Load the entity with the given identifier
						trValue = utils.find(dbValue.getClass(), trValueId);
					} else {
						// Use the persistent value because the object identities are equals
						trValue = dbValue;
					}
				}
			}

			if (trValue != dbValue) {
				if (logger.isTraceEnabled()) {
					logger.trace(String.format("Setting property %s of %s to %s", propertyName, dbObj, trValue));
				}
				dbPropertyAccessor.setPropertyValue(propertyName, trValue);
			}
		}

		return dbObj;
	}

	/**
	 * Returns the {@code EntityPersisterConfiguration} that should be used.
	 *
	 * @return the {@code EntityPersisterConfiguration} to use
	 */
	@Nonnull
	public EntityPersisterConfiguration getConfig() {
		return config;
	}

	/**
	 * Sets the {@code EntityPersisterConfiguration} that should be used.
	 *
	 * @param config the {@code EntityPersisterConfiguration} to use
	 */
	public void setConfig(@Nonnull EntityPersisterConfiguration config) {
		this.config = config;
	}

	/**
	 * Sets a flag indicating that the default {@link EntityPersister}s should be initialized upon initialization.
	 *
	 * @param registerDefaultEntityPersisters
	 *         {@code true} if the default {@code EntityPersister}s should be registered, {@code false} otherwise
	 */
	public void setRegisterDefaultEntityPersisters(boolean registerDefaultEntityPersisters) {
		this.registerDefaultEntityPersisters = registerDefaultEntityPersisters;
	}

	/**
	 * Returns a modifiable map containing all registered {@code EntityPersister}s.
	 *
	 * @return the registered {@code EntityPersister}s
	 */
	@Nonnull
	public Map&lt;Class&lt;?&gt;, AbstractEntityPersister&lt;?&gt;&gt; getPersisterMap() {
		if (persisterMap == null) {
			persisterMap = new LinkedHashMap&lt;Class&lt;?&gt;, AbstractEntityPersister&lt;?&gt;&gt;();
		}
		return persisterMap;
	}

	/**
	 * Sets the mapping of the {@code AbstractEntityPersister}s that should be used.
	 *
	 * @param persisterMap the entity persister mapping
	 */
	public void setPersisterMap(@Nonnull Map&lt;Class&lt;?&gt;, AbstractEntityPersister&lt;?&gt;&gt; persisterMap) {
		this.persisterMap = persisterMap;
	}

	/**
	 * Returns an {@link EntityPersister} that is capable of processing instances
	 * of the given type.
	 *
	 * @param clazz the type of the object to process
	 * @return the EntityPersister or {@code null} if there is none available.
	 */
	@Nullable
	@SuppressWarnings("unchecked")
	public &lt;T&gt; AbstractEntityPersister&lt;T&gt; getEntityPersister(@Nullable Class&lt;? extends T&gt; clazz) {
		AbstractEntityPersister&lt;T&gt; entityPersister = (AbstractEntityPersister&lt;T&gt;) getPersisterMap().get(clazz);
		if (entityPersister == null &amp;&amp; clazz != null &amp;&amp; !getPersisterMap().containsKey(clazz)) {
			entityPersister = findEntityPersister(clazz);

			if (entityPersister == null) {
				for (Map.Entry&lt;Class&lt;?&gt;, AbstractEntityPersister&lt;?&gt;&gt; entry : persisterMap.entrySet()) {
					if (entry.getValue() instanceof DynamicEntityPersister) {
						if (((DynamicEntityPersister&lt;?&gt;) entry.getValue()).supports(clazz)) {
							entityPersister = (AbstractEntityPersister&lt;T&gt;) entry.getValue();
							break;
						}
					}
				}
			}
			if (logger.isDebugEnabled()) {
				logger.trace(String.format("Registering %s for type %s", entityPersister, clazz.getName()));
			}
			getPersisterMap().put(clazz, entityPersister);
		}
		return entityPersister;
	}

	@Nullable
	@SuppressWarnings("unchecked")
	private &lt;T&gt; AbstractEntityPersister&lt;T&gt; findEntityPersister(@Nonnull Class&lt;? extends T&gt; clazz) {
		try {
			for (Map.Entry&lt;Class&lt;?&gt;, AbstractEntityPersister&lt;?&gt;&gt; entry : getPersisterMap().entrySet()) {
				if (entry.getKey().isAssignableFrom(clazz)) {
					return (AbstractEntityPersister&lt;T&gt;) entry.getValue();
				}
			}
		} catch (ConcurrentModificationException e) {
			/*
			 * The persister map is not synchronized because of the performance requirements.
			 * Thus, a ConcurrentModificationException may rarely happen while iterating through it.
			 * Therefore, the exception is ignored and Dormancy attempts to retry finding an appropriate EntityPersister.
			 */
			return findEntityPersister(clazz);
		}
		return null;
	}

	@Override
	@SuppressWarnings("unchecked")
	public void setApplicationContext(@Nonnull ApplicationContext applicationContext) {
		Map&lt;String, AbstractDormancyUtils&gt; utilsMap = applicationContext.getBeansOfType(AbstractDormancyUtils.class);
		if (utilsMap.size() &gt; 1) {
			throw new IllegalStateException(String.format("Cannot initialize %s: Multiple beans of type %s found: %s",
					getClass(), AbstractDormancyUtils.class.getName(), utilsMap.keySet()));
		} else if (utilsMap.size() == 1) {
			this.utils = utilsMap.get(utilsMap.keySet().iterator().next());
		}

		initialize();
		// Retrieve all AbstractEntityPersisters from the application context and register them
		Map&lt;String, AbstractEntityPersister&gt; map = applicationContext.getBeansOfType(AbstractEntityPersister.class);
		for (AbstractEntityPersister&lt;?&gt; entityPersister : map.values()) {
			addEntityPersister(entityPersister);
		}
	}

	/**
	 * Registers the given {@link AbstractEntityPersister} for certain types.&lt;br/&gt;
	 * The {@link AbstractEntityPersister} is registered for every type returned by
	 * {@link AbstractEntityPersister#getSupportedTypes()} and the parameter types.
	 * Furthermore, the type of the {@link AbstractEntityPersister} itself is registered so it can be used by in
	 * {@link at.dormancy.aop.PersistenceEndpoint#types()}.
	 *
	 * @param entityPersister the EntityPersister to register
	 * @param types           the types of objects supported by the EntityPersister (may be {@code null})
	 * @see #addEntityPersister(Class, Class[])
	 */
	public void addEntityPersister(@Nonnull AbstractEntityPersister&lt;?&gt; entityPersister, @Nullable Class&lt;?&gt;... types) {
		if (CollectionUtils.isNotEmpty(entityPersister.getSupportedTypes())) {
			for (Class&lt;?&gt; type : entityPersister.getSupportedTypes()) {
				getPersisterMap().put(type, entityPersister);
			}
		}
		if (ArrayUtils.isNotEmpty(types)) {
			// Register the given types for advanced customization
			for (Class&lt;?&gt; type : types) {
				getPersisterMap().put(type, entityPersister);
			}
		}
		// Register the unproxified persister itself to make it available for PersistenceEndpoint
		getPersisterMap().put(AopUtils.getTargetClass(entityPersister), entityPersister);
	}

	/**
	 * Registers an instance of the given {@link AbstractEntityPersister} type for certain types.&lt;br/&gt;
	 * The {@link AbstractEntityPersister} is registered for every type returned by
	 * {@link AbstractEntityPersister#getSupportedTypes()} and the parameter types.
	 * Furthermore, the type of the {@link AbstractEntityPersister} itself is registered so it can be used by in
	 * {@link at.dormancy.aop.PersistenceEndpoint#types()}.
	 *
	 * @param entityPersisterClass the type of the EntityPersister to register
	 * @param types                the types of objects supported by the EntityPersister (may be {@code null})
	 * @see #addEntityPersister(AbstractEntityPersister, Class[])
	 */
	@SuppressWarnings("unchecked")
	public void addEntityPersister(@Nonnull Class&lt;? extends AbstractEntityPersister&gt; entityPersisterClass, @Nullable Class&lt;?&gt;... types) {
		Constructor&lt;? extends AbstractEntityPersister&gt; constructor = ClassUtils.getConstructorIfAvailable(entityPersisterClass, Dormancy.class);
		AbstractEntityPersister&lt;?&gt; entityPersister = constructor != null ? BeanUtils.instantiateClass(constructor, this) : BeanUtils.instantiateClass(entityPersisterClass);
		if (entityPersister instanceof AbstractContainerPersister) {
			((AbstractContainerPersister&lt;?&gt;) entityPersister).setPersistentUnitProvider(persistenceUnitProvider);
		}
		addEntityPersister(entityPersister, types);
	}

	/**
	 * Returns the Dormancy utilities associated with this instance.
	 *
	 * @return the Dormancy utilities to use
	 */
	@Nonnull
	public AbstractDormancyUtils&lt;PU, PC, PMD, PersistenceUnitProvider&lt;PU, PC, PMD&gt;&gt; getUtils() {
		return utils;
	}
}

  </pre>
</div>
<div id="footer">
Generated by <a href="http://code.google.com/p/doclava/">Doclava</a>.
</div> <!-- end footer -->

</div> <!-- jd-content -->

</div><!-- end doc-content -->

</div> <!-- end body-content --> 

<script type="text/javascript">
init(); /* initialize doclava-developer-docs.js */
</script>

</body>
</html>
